package com.gatesim;

import java.util.ArrayList;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Point;
import android.util.Log;



/**
 * Gate Class
 * 
 * A Gate object can connect to other gates and
 * relay charges like a gate in computer hardware.
 * It has an array of 2 parents from where it gets 
 * its charge and an ArrayList of children to which
 * it sends its charge. 
 * 
 * @author Katharine Walsh & Alfred Tarng
 *
 */

public abstract class Gate{
	
	private static int gateID = 0;
	public static Resources resources;
	public Wire parents[]; //Assume 2 input pins for now
	//CHANGE TO CHILDREN, and ArrayList, multiple children okay!
	public ArrayList<Wire> children;
	public Point corner;
    public Point center;
	public InputConnection topPin;
	public InputConnection botPin;
	public OutputConnection fntPin;
	public int width; 
	public int height;
	public int id;
	public boolean selected;
	
	protected final int delayValue = 1;
	
	public int _gCount = 0;
	protected Integer personalDelay;
	
	protected Gate(Point c){
		parents = new Wire[2]; //Assuming 2 pins for now
		parents[0] = null;
		parents[1] = null;
		children = new ArrayList<Wire>();
		
		corner = new Point();
		corner = new Point();
		center = c;
		
		id = gateID;
		gateID++;		
		selected = false;
		personalDelay = new Integer(0);
	}
    
    public boolean hasCharge(){
    	return fntPin.hasCharge();
    }
    
    /*
     * The below methods deal with adding
     * relationships between gates such as
     * children and parents.
     */
    public boolean addParent(Wire p){
    	if(this.topPin.isSelected()){
    		return addTopParent(p);
    	}
    	if(this.botPin.isSelected()){
    		return addBotParent(p);
    	}
    	return false;
    }
    
    public boolean addTopParent(Wire p){
		if(parents[0] == null || !topPin.isOccupied()){
			parents[0] = p;
			return true;
		}
		return false;
    }
    
    public boolean addBotParent(Wire p){
		if(parents[1] == null || !botPin.isOccupied()){
			parents[1] = p;
			return true;
		}
    	return false;
    }
    
    public void addChild(Wire c){
    	children.add(c);
    }

    public void disconnectWire(Wire w){
    	ArrayList<Wire> wiresToRemove = new ArrayList<Wire>();
    	for(int i = 0; i < children.size(); i++){
    		if(w == children.get(i)){
    			wiresToRemove.add(children.get(i));
    		}
    	}
    	children.removeAll(wiresToRemove); 
    	if(parents[0] == w){
    		parents[0] = null;
    	}
    	if(parents[1] == w){
    		parents[1] = null;
    	}
    	
    	if(w.getDest() != null)
			w.getDest().unoccupy();
		if(w.getSource() != null)
			w.getSource().unoccupy();
		
        personalDelay = new Integer(0);
    }
    
    /*
     * Below are the mathematical functions for the Gate
     * class. They are used to see if the user is touching
     * near a point.
     */  
	public static float distance(Point p, float x, float y){
		int result = (int)Math.sqrt((pow(p.x-x,2)+pow(p.y-y,2)));
		return result;
	}
	
	private static float pow(float a, float b){
		float result = 1;
		for(int i = 0; i < b; i++){
			result = result*a;
		}
		return result;
	}
	
	/**
	 * Below are the getters and setters for
	 * the Gate class.
	 */
	public static void setResources(Resources r){
		resources = r;
	}
	public void setWidth(int w){
		width = w;
	}
	public void setHeight(int h){
		height = h;
	}
	public int getWidth(){
		return width;
	}
	public int getHeight(){
		return height;
	}
	
    public Point getCenter(){
        return center;
    }
    
    public void updatePosition(Point p){
        center = p;
        corner.set( center.x - (width/2), center.y - (height/2) );
        recalcPins();
    }
	
	public boolean isGate(){ 
		return true; 
	}
	
	public boolean isVolt(){
		return false;
	}
	
	//Abstract Methods to be overridden by inheriting classes
//	public abstract int produceOut(); //throws UnknownParentChargeException;
    public abstract int produceOut();//{ i = new Integer(i.intValue() + 1); return produceOut(); };
	public abstract void draw(Canvas c, Resources r, boolean simulationMode);
	public abstract void recalcPins();
	public abstract void endSimulationMode();
	public abstract void select(boolean b, boolean simulationMode);

    public int signalOut() {  return 0; }

}
